parser grammar PLCSTParser;
options {
	tokenVocab = PLCSTLexer;
}

startpoint :
    (pOU_Decl | prog_Decl | sFC | config_Decl)* EOF;

//Numeric literal

constant : numeric_Literal | char_Literal | time_Literal | bit_Str_Literal | bool_Literal;

numeric_Literal : int_Literal | real_Literal;

int_Literal : ( Int_Type_Name TypeSign )? (Unsigned_Int | Signed_Int | Binary_Int | Octal_Int | Hex_Int );

real_Literal : ( Real_Type_Name TypeSign )? Science_real;

bool_Literal : ( Bool_Type_Name TypeSign )? Const_bool;

//Character String literal &  Two-character combinations in character strings
char_Str : (STRING TypeSign)? S_Byte_Char_Str ;

wChar_Str : (WSTRING TypeSign)? D_Byte_Char_Str ;

char_Literal : char_Str | wChar_Str;

//Duration literals &  Date and time of day literals

time_Literal : Duration | Time_Of_Day | Date | Date_And_Time;

// Elementary data types
bit_Str_Literal : Multibits_Type_Name TypeSign ( Unsigned_Int | Binary_Int | Octal_Int | Hex_Int );

numeric_Type_Name : Int_Type_Name | Real_Type_Name;

string_Type_Name : SString_Type_Name | WString_Type_Name | CHAR | WCHAR;

bit_Str_Type_Name : Bool_Type_Name | Multibits_Type_Name;

data_Type_Access : elem_Type_Name | derived_Type_Access;

elem_Type_Name : numeric_Type_Name | bit_Str_Type_Name
            | string_Type_Name | Date_Type_Name | Time_Type_Name;

nestedNameSpecifier : namespace_Name Dot;

derived_Type_Access : nestedNameSpecifier *
                        simple_Type_Name | subrange_Type_Name | enum_Type_Name | //old single_Elem_Type_Access
                        array_Type_Name | struct_Type_Name | string_Type_Name |
                        class_Type_Name | ref_Type_Name | interface_Type_Name ;

struct_Type_Access : nestedNameSpecifier * struct_Type_Name;


data_Type_Decl : TYPE ( type_Decl Semi )+ END_TYPE;

type_Decl : simple_Type_Decl | subrange_Type_Decl | enum_Type_Decl
                | array_Type_Decl | struct_Type_Decl
                | str_Type_Decl | ref_Type_Decl;

simple_Type_Decl : simple_Type_Name Colon simple_Spec_Init;

nested_Simple_Type_Decl : nestedNameSpecifier * simple_Type_Name;

simple_Spec_Init : simple_Spec ( Assign constant_Expr )?;

simple_Spec : elem_Type_Name | nested_Simple_Type_Decl;

subrange_Type_Decl : subrange_Type_Name Colon subrange_Spec_Init;

subrange_Spec_Init : subrange_Spec ( Assign Signed_Int )?;

subrange_Spec : Int_Type_Name LeftParen subrange RightParen | nestedNameSpecifier * subrange_Type_Name;

subrange : constant_Expr RangeDot constant_Expr;

enum_Type_Decl : enum_Type_Name Colon ( ( elem_Type_Name ? named_Spec_Init ) | enum_Spec_Init );

named_Spec_Init : LeftParen enum_Value_Spec ( Comma enum_Value_Spec )* RightParen ( Assign enum_Value )?;

enum_Spec_Init : ( ( LeftParen identifier ( Comma identifier )* RightParen )
                    | nestedNameSpecifier * enum_Type_Name ) ( Assign enum_Value )?;
enum_Value_Spec : identifier ( Assign ( int_Literal | constant_Expr ) )?;

enum_Value : enum_Type_Name TypeSign identifier;

array_Type_Decl : array_Type_Name Colon array_Spec_Init;

array_Spec_Init : array_Spec ( Assign array_Init )?;

array_Spec : nested_Array_Type_Name | direct_Array_Type_Name;

nested_Array_Type_Name : nestedNameSpecifier * array_Type_Name;

direct_Array_Type_Name : ARRAY LeftBracket subrange ( Comma subrange )* RightBracket OF data_Type_Access;

array_Init : LeftBracket array_Elem_Init ( Comma array_Elem_Init )* RightBracket;

array_Elem_Init : array_Elem_Init_Value | mult_Array_Elem_Init_Value;

mult_Array_Elem_Init_Value : Unsigned_Int LeftParen array_Elem_Init_Value ? RightParen;

array_Elem_Init_Value : constant_Expr | enum_Value | struct_Init | array_Init;

struct_Type_Decl : struct_Type_Name Colon struct_Spec;

nested_Struct_Type_Decl : nestedNameSpecifier * struct_Type_Name;

struct_Spec : struct_Decl | struct_Spec_Init;

struct_Spec_Init : nested_Struct_Type_Decl ( Assign struct_Init )?;

struct_Decl :STRUCT OVERLAP ? ( struct_Elem_Decl Semi )+ END_STRUCT;

struct_Elem_Decl : struct_Elem_Name ( located_At Multibit_Part_Access ? )? Colon
                ( simple_Spec_Init | subrange_Spec_Init | enum_Spec_Init | array_Spec_Init
                | struct_Spec_Init );

struct_Init : LeftParen struct_Elem_Init ( Comma struct_Elem_Init )* RightParen;

struct_Elem_Init : struct_Elem_Name Assign ( constant_Expr | enum_Value | array_Init | struct_Init | ref_Value );

str_Type_Decl : string_Type_Name Colon string_Type_Name ( Assign char_Str )?;


// Directly represented variables
//nothing

//Reference operations
ref_Type_Decl : ref_Type_Name Colon ref_Spec_Init;

ref_Spec_Init : ref_Spec ( Assign ref_Value )?;

ref_Spec : REF_TO + data_Type_Access;

ref_Type_Access : nestedNameSpecifier * ref_Type_Name;

ref_Value : ref_Addr | Null;

ref_Addr : REF LeftParen ( symbolic_Variable | fB_Instance_Name | class_Instance_Name ) RightParen;

ref_Assign : ref_Name Assign ( ref_Name | ref_Deref | ref_Value );

ref_Deref : ref_Name Caret +;

//Declaration of variables/Table 14 – Initialization of variables

variable : Direct_Variable | symbolic_Variable;

symbolic_Variable : ( ( THIS Dot ) | nestedNameSpecifier + )? ( var_Access | multi_Elem_Var );

var_Access : variable_Name | ref_Deref;

multi_Elem_Var : var_Access ( subscript_List | struct_Variable )+;

subscript_List : LeftBracket subscript ( Comma subscript )* RightBracket;

subscript : expression;

struct_Variable : Dot struct_Elem_Select;

struct_Elem_Select : var_Access;

input_Decls : VAR_INPUT ( RETAIN | NON_RETAIN )? ( input_Decl Semi )* END_VAR;

input_Decl : var_Decl_Init | edge_Decl | array_Conform_Decl;

var_Decl_Init : common_Var_Decl_Init | interface_Spec_Init;

common_Var_Decl_Init : variable_List Colon (
                                       simple_Spec_Init |
                                       ref_Spec_Init |
                                       array_Spec_Init |
                                       struct_Spec_Init |
                                       fB_Spec_Init
                                       );

edge_Decl : variable_List Colon Bool_Type_Name ( R_EDGE | F_EDGE );

ref_Var_Decl : variable_List Colon ref_Spec;

interface_Var_Decl : variable_List Colon interface_Type_Access;

variable_List : variable_Name ( Comma variable_Name )*;

array_Conformand : ARRAY LeftBracket Star ( Comma Star )* RightBracket OF data_Type_Access;

array_Conform_Decl : variable_List Colon array_Conformand;

fB_Decl_No_Init : variable_List Colon fB_Type_Access;

//fB_Decl_Init : fB_Decl_No_Init ( Assign struct_Init )?;

fB_Spec_Init : fB_Type_Access ( Assign struct_Init )?;

fB_Instance_Name : nestedNameSpecifier * fB_Name Caret *;

output_Decls : VAR_OUTPUT ( RETAIN | NON_RETAIN )? ( output_Decl Semi )* END_VAR;

output_Decl : var_Decl_Init | array_Conform_Decl;

in_Out_Decls : VAR_IN_OUT ( in_Out_Var_Decl Semi )* END_VAR;

in_Out_Var_Decl : var_Decl | array_Conform_Decl | fB_Decl_No_Init;

var_Decl : variable_List Colon ( simple_Spec | str_Var_Decl | array_Var_Decl | struct_Var_Decl );

array_Var_Decl : variable_List Colon array_Spec;

struct_Var_Decl : variable_List Colon struct_Type_Access;

var_Decls : VAR CONSTANT ? access_Spec ? ( var_Decl_Init Semi )* END_VAR;

retain_Var_Decls : VAR RETAIN access_Spec ? ( var_Decl_Init Semi )* END_VAR;

loc_Var_Decls : VAR ( CONSTANT | RETAIN | NON_RETAIN )? ( loc_Var_Decl Semi )* END_VAR;

loc_Var_Decl : variable_Name ? located_At Colon loc_Var_Spec_Init;

temp_Var_Decls : VAR_TEMP ( ( var_Decl | ref_Var_Decl | interface_Var_Decl ) Semi )* END_VAR;

external_Var_Decls : VAR_EXTERNAL CONSTANT ? ( external_Decl Semi )* END_VAR;

external_Decl : global_Var_Name Colon
( simple_Spec | array_Spec | struct_Type_Access | fB_Type_Access | ref_Type_Access );

global_Var_Decls : VAR_GLOBAL ( CONSTANT | RETAIN )? ( global_Var_Decl Semi )* END_VAR;

global_Var_Decl : global_Var_Spec Colon ( loc_Var_Spec_Init | fB_Type_Access );

global_Var_Spec : ( global_Var_Name ( Comma global_Var_Name )* ) | ( global_Var_Name located_At );

loc_Var_Spec_Init : simple_Spec_Init | array_Spec_Init
                    | struct_Spec_Init | s_Byte_Str_Spec | d_Byte_Str_Spec;

located_At : AT Direct_Variable;

str_Var_Decl : s_Byte_Str_Var_Decl | d_Byte_Str_Var_Decl;

s_Byte_Str_Var_Decl : variable_List Colon s_Byte_Str_Spec;

s_Byte_Str_Spec : SString_Type_Name ( Assign S_Byte_Char_Str )?;

d_Byte_Str_Var_Decl : variable_List Colon d_Byte_Str_Spec;

d_Byte_Str_Spec : WString_Type_Name ( Assign D_Byte_Char_Str )?;

loc_Partly_Var_Decl : VAR ( RETAIN | NON_RETAIN )? loc_Partly_Var * END_VAR;

loc_Partly_Var : variable_Name AT Var_Location Colon var_Spec Semi;

var_Spec : simple_Spec | array_Spec | struct_Type_Access
          | ( SString_Type_Name | WString_Type_Name );


//Function declaration
func_Name : std_Func_Name | derived_Func_Name;

func_Access : nestedNameSpecifier * func_Name;

func_Decl : FUNCTION derived_Func_Name ( Colon data_Type_Access )? using_Directive *
( iO_Var_Decls | func_Var_Decls | temp_Var_Decls )* func_Body END_FUNCTION;

iO_Var_Decls : input_Decls | output_Decls | in_Out_Decls;

func_Var_Decls : external_Var_Decls | var_Decls;

//unsupport ladder_Diagram | fB_Diagram | Instruction_List | Other_Languages;
func_Body : stmt_List;

//Function block type declaration & Function block instance declaration
fB_Type_Name : Std_FB_Name | derived_FB_Name;

fB_Type_Access : nestedNameSpecifier * fB_Type_Name;

fB_Decl : FUNCTION_BLOCK ( FINAL | ABSTRACT )? derived_FB_Name using_Directive *
        ( EXTENDS ( fB_Type_Access | class_Type_Access ) )?
        ( IMPLEMENTS interface_Name_List )?
        ( fB_IO_Var_Decls | func_Var_Decls | temp_Var_Decls | other_Var_Decls )*
        ( method_Decl )* fB_Body END_FUNCTION_BLOCK;

fB_IO_Var_Decls : fB_Input_Decls | fB_Output_Decls | in_Out_Decls;

fB_Input_Decls : VAR_INPUT ( RETAIN | NON_RETAIN )? ( fB_Input_Decl Semi )* END_VAR;

fB_Input_Decl : var_Decl_Init | edge_Decl | array_Conform_Decl;

fB_Output_Decls : VAR_OUTPUT ( RETAIN | NON_RETAIN )? ( fB_Output_Decl Semi )* END_VAR;

fB_Output_Decl : var_Decl_Init | array_Conform_Decl;

other_Var_Decls : retain_Var_Decls | no_Retain_Var_Decls | loc_Partly_Var_Decl;

no_Retain_Var_Decls : VAR NON_RETAIN access_Spec ? ( var_Decl_Init Semi )* END_VAR;

//unsupport SFC | Ladder_Diagram | FB_Diagram | Instruction_List | Other_Languages
fB_Body :  stmt_List ;

method_Decl : METHOD access_Spec ( FINAL | ABSTRACT )? OVERRIDE ?
              method_Name ( Colon data_Type_Access )?
              ( iO_Var_Decls | func_Var_Decls | temp_Var_Decls )* func_Body END_METHOD;

//Class &  Textual call of methods – Formal and non-formal parameter list

access_Spec : PUBLIC | PROTECTED | PRIVATE | INTERNAL;

class_Decl : CLASS ( FINAL | ABSTRACT )? class_Type_Name using_Directive *
( EXTENDS class_Type_Access )? ( IMPLEMENTS interface_Name_List )?
( func_Var_Decls | other_Var_Decls )* ( method_Decl )* END_CLASS;

class_Type_Access : nestedNameSpecifier * class_Type_Name;

class_Instance_Name : nestedNameSpecifier * class_Name Caret *;

interface_Decl : INTERFACE interface_Type_Name using_Directive *
( EXTENDS interface_Name_List )? method_Prototype * END_INTERFACE;

method_Prototype : METHOD method_Name ( Colon data_Type_Access )? iO_Var_Decls * END_METHOD;

//TODO: interface_Spec_Init不清除什么含义,翻译到此处时再作修改
interface_Spec_Init : variable_List ( Assign interface_Value )?;

interface_Value : symbolic_Variable | fB_Instance_Name | class_Instance_Name | Null;

interface_Name_List : interface_Type_Access ( Comma interface_Type_Access )*;

interface_Type_Access : nestedNameSpecifier * interface_Type_Name;

//Program declaration
prog_Decl : PROGRAM prog_Type_Name
            ( iO_Var_Decls | func_Var_Decls | temp_Var_Decls | other_Var_Decls
            | loc_Var_Decls | prog_Access_Decls )* fB_Body END_PROGRAM;

prog_Type_Access : nestedNameSpecifier * prog_Type_Name;

prog_Access_Decls : VAR_ACCESS ( prog_Access_Decl Semi )* END_VAR;

prog_Access_Decl : access_Name Colon symbolic_Variable Multibit_Part_Access ?
             Colon data_Type_Access Access_Direction ?;

//Sequential Function Chart (SFC)
sFC : sfc_Network +;

sfc_Network : initial_Step ( step | transition | action )*;

initial_Step : INITIAL_STEP step_Name Colon ( action_Association Semi )* END_STEP;

step : STEP step_Name Colon ( action_Association Semi )* END_STEP;

action_Association : action_Name LeftParen action_Qualifier ? ( Comma indicator_Name )* RightParen;

action_Qualifier : ACTION_QUALIFIER | ( ACTION_TIME_QUALIFIER Comma action_Time );

action_Time : Duration | variable_Name;

transition : TRANSITION transition_Name ? ( LeftParen PRIORITY Assign Unsigned_Int RightParen )?
            FROM steps TO steps Colon transition_Cond END_TRANSITION;



steps : step_Name | LeftParen step_Name ( Comma step_Name )+ RightParen;

//unsupport FBD_Network, LD_Rung and IL_Simple_Inst
transition_Cond : Assign expression Semi;

action : ACTION action_Name Colon fB_Body END_ACTION;

// Configuration and resource declaration


config_Decl : CONFIGURATION config_Name global_Var_Decls ?
             ( single_Resource_Decl | resource_Decl + ) access_Decls ? config_Init ?
             END_CONFIGURATION;

resource_Decl : RESOURCE resource_Name ON resource_Type_Name
                 global_Var_Decls ? single_Resource_Decl
                 END_RESOURCE;

single_Resource_Decl : ( task_Config Semi )* ( prog_Config Semi )+;



access_Decls : VAR_ACCESS ( access_Decl Semi )* END_VAR;

access_Decl : access_Name Colon access_Path Colon data_Type_Access Access_Direction ?;

access_Path : ( resource_Name Dot )? Direct_Variable
                | ( resource_Name Dot )? ( prog_Name Dot )?
                ( ( fB_Instance_Name | class_Instance_Name ) Dot )* symbolic_Variable;

global_Var_Access : ( resource_Name Dot )? global_Var_Name ( Dot struct_Elem_Name )?;


prog_Output_Access : prog_Name Dot symbolic_Variable;

task_Config : TASK task_Name task_Init;

task_Init : LeftParen ( SINGLE Assign data_Source Comma )?
            ( INTERVAL Assign data_Source Comma )?
            PRIORITY Assign Unsigned_Int RightParen;

data_Source : constant | global_Var_Access | prog_Output_Access | Direct_Variable;

prog_Config : PROGRAM ( RETAIN | NON_RETAIN )? prog_Name ( WITH task_Name )? Colon
             prog_Type_Access ( LeftParen prog_Conf_Elems RightParen )?;

prog_Conf_Elems : prog_Conf_Elem ( Comma prog_Conf_Elem )*;

prog_Conf_Elem : fB_Task | prog_Cnxn;

fB_Task : fB_Instance_Name WITH task_Name;

prog_Cnxn : symbolic_Variable Assign prog_Data_Source | symbolic_Variable LeftAssign data_Sink;

prog_Data_Source : constant | enum_Value | global_Var_Access | Direct_Variable;

data_Sink : global_Var_Access | Direct_Variable;

config_Init : VAR_CONFIG ( config_Inst_Init Semi )* END_VAR;

config_Inst_Init : resource_Name Dot prog_Name Dot ( ( fB_Instance_Name | class_Instance_Name ) Dot )*
                ( variable_Name located_At ? Colon
                loc_Var_Spec_Init
                | ( ( fB_Instance_Name Colon fB_Type_Access )
                | ( class_Instance_Name Colon class_Type_Access ) ) Assign struct_Init );

//Namespace
namespace_Decl : NAMESPACE INTERNAL ? namespace_H_Name using_Directive * namespace_Elements END_NAMESPACE;

namespace_Elements : ( data_Type_Decl | func_Decl | fB_Decl | class_Decl | interface_Decl | namespace_Decl )+;

namespace_H_Name : namespace_Name ( Dot namespace_Name )*;

using_Directive : USING namespace_H_Name ( Comma namespace_H_Name )* Semi;

pOU_Decl : using_Directive *
            ( global_Var_Decls | data_Type_Decl | access_Decls
            | func_Decl | fB_Decl | class_Decl | interface_Decl
            | namespace_Decl )+;

//Instruction List (IL)
//pass

// Language Structured Text (ST)
expression : xor_Expr ( OR xor_Expr )*;

constant_Expr : expression;
 // a constant expression must evaluate to a constant value at compile time

xor_Expr : and_Expr ( XOR and_Expr )*;

and_Expr : compare_Expr ( ( AndSign | AND ) compare_Expr )*;

compare_Expr : ( equ_Expr ( ( Equal | NotEqual ) equ_Expr )* );

equ_Expr : add_Expr ( ( Less | Greater | LessEqual | GreaterEqual ) add_Expr )*;

add_Expr : term ( ( Plus | Minus ) term )*;

term : power_Expr ( (Star | Div | MOD) power_Expr )*;

power_Expr : unary_Expr ( StarStar unary_Expr )*;

unary_Expr : (Minus | Plus | NOT) ? primary_Expr;

paren_Surrounded_Expr : LeftParen expression RightParen;

//TODO: Identifider 可以匹配到enum_Value和variable_Access, 暂时加入identifier占位
primary_Expr : constant | identifier | enum_Value | variable_Access | func_Call | ref_Value | paren_Surrounded_Expr;

variable_Access : variable Multibit_Part_Access ?;

callable_Obj_Params_Assign : LeftParen ( param_Assign ( Comma param_Assign )* )? RightParen;

func_Call : func_Access callable_Obj_Params_Assign;

stmt_List : ( stmt ? Semi )*;

stmt : assign_Stmt | subprog_Ctrl_Stmt | selection_Stmt | iteration_Stmt;

assign_Stmt : var_Assign | ref_Assign | assignment_Attempt;

var_Assign : variable Assign expression;

assignment_Attempt : ( ref_Name | ref_Deref ) QuestionEqual ( ref_Name | ref_Deref | ref_Value );

inside_Callable_Obj : ( THIS Dot )? ( ( ( fB_Instance_Name | class_Instance_Name ) Dot )+ ) method_Name;

callable_Obj : fB_Instance_Name | method_Name | THIS | inside_Callable_Obj;

invocation : callable_Obj callable_Obj_Params_Assign;

subprog_Ctrl_Stmt : func_Call | invocation | SUPER LeftParen RightParen | RETURN;

param_Assign : common_Param_Assign | ref_Param_Assign | other_Param_Assign;

common_Param_Assign : ( variable_Name Assign )? expression;

ref_Param_Assign : ref_Assign;

other_Param_Assign : NOT ? variable_Name LeftAssign variable;

selection_Stmt : iF_Stmt | case_Stmt;

iF_Stmt : IF expression THEN stmt_List ( ELSIF expression THEN stmt_List )* ( ELSE stmt_List )? END_IF;

case_Stmt : CASE expression OF case_Selection + ( ELSE stmt_List )? END_CASE;

case_Selection : case_List Colon stmt_List;

case_List : case_List_Elem ( Comma case_List_Elem )*;

case_List_Elem : subrange | constant_Expr;

iteration_Stmt : for_Stmt | while_Stmt | repeat_Stmt | EXIT | CONTINUE;

for_Stmt : FOR control_Variable Assign for_List DO stmt_List END_FOR;

for_List : expression TO expression ( BY expression )?;

while_Stmt : WHILE expression DO stmt_List END_WHILE;

repeat_Stmt : REPEAT stmt_List UNTIL expression END_REPEAT;

//Function declaration
std_Func_Name : TRUNC | ABS | SQRT | LN | LOG | EXP
            | SIN | COS | TAN | ASIN | ACOS | ATAN | ATAN2
            | ADD | SUB | MUL | DIV | MOD | EXPT | MOVE
            | SHL | SHR | ROL | ROR
            | AND | OR | XOR | NOT
            | SEL | MAX | MIN | LIMIT | MUX
            | GT | GE | EQ | LE | LT | NE
            | LEN | LEFT | RIGHT | MID | CONCAT | INSERT | DELETE | REPLACE | FIND;
 // incomplete list

simple_Type_Name : identifier;

subrange_Type_Name : identifier;

enum_Type_Name : identifier;

array_Type_Name : identifier;

struct_Type_Name : identifier;

struct_Elem_Name : identifier;

ref_Name : identifier;

ref_Type_Name : identifier;

variable_Name : identifier;

fB_Name : identifier;

global_Var_Name : identifier;

derived_Func_Name : identifier;

derived_FB_Name : identifier;

method_Name : identifier;

class_Type_Name : identifier;

class_Name : identifier;

interface_Type_Name : identifier;

//interface_Name : identifier;

prog_Type_Name : identifier;

step_Name : identifier;

action_Name : identifier;

transition_Name : identifier;

config_Name : identifier;

resource_Type_Name : identifier;

resource_Name : identifier;

access_Name : identifier;

prog_Name : identifier;

task_Name : identifier;

namespace_Name : identifier;

control_Variable : identifier;

indicator_Name : variable_Name;

identifier : Identifier | ACTION_QUALIFIER | ACTION_TIME_QUALIFIER;